package org.yunai.yfserver.object;

import java.lang.reflect.Array;
import java.util.BitSet;

/**
 * 泛型属性数组
 * User: yunai
 * Date: 13-5-2
 * Time: 下午4:45
 */
public class PropertyArray<T> {

    /**
     * 数值数组
     */
    private final T[] values;
    /**
     * 数值是否修改标识集合
     */
    private final BitSet bitSet;

    @SuppressWarnings("unchecked")
    public PropertyArray(Class<T> clazz, int size) {
        this.values = (T[]) Array.newInstance(clazz, size);
        this.bitSet = new BitSet(size);
    }

    /**
     * 从指定的泛型属性数组src拷贝数据到本实例
     *
     * @param src 指定泛型属性数组
     */
    public void copyFrom(PropertyArray<T> src) {
        System.arraycopy(src.values, 0, values, 0, values.length);
        bitSet.set(0, values.length, true);
    }

    /**
     * @return 数值数组是否修改
     */
    public boolean isChanged() {
        return bitSet.isEmpty();
    }

    /**
     * 标记数值数组未修改
     */
    public void resetChanged() {
        bitSet.clear();
    }

    /**
     * 清理掉指定位置的修改标记
     *
     * @param index 指定位置
     */
    public void resetChanged(int index) {
        bitSet.clear(index);
    }

    /**
     * 取得位置index对应的值
     *
     * @param index 位置
     * @return 位置index对应的值
     * @throws ArrayIndexOutOfBoundsException 当index < 0 或 index >=size 时会抛出此异常
     */
    public T get(int index) {
        return values[index];
    }

    /**
     * 设置index对应值为newValue，并返回是否修改
     *
     * @param index    位置
     * @param newValue 新值
     * @return 是否修改
     * @throws ArrayIndexOutOfBoundsException 当index < 0 或 index >=size 时会抛出此异常
     */
    public boolean set(int index, T newValue) {
        T oldValue = get(index);
        boolean changed = false;
        if (oldValue != null) {
            changed = !oldValue.equals(newValue);
        } else if (newValue != null) {
            changed = true;
        }
        if (changed) {
            values[index] = newValue;
            bitSet.set(index);
        }
        return changed;
    }

    /**
     * @return 取得属性个数
     */
    public int size() {
        return values.length;
    }

    /**
     * @return 被修改过的属性索引以及其对应的值
     */
    @SuppressWarnings("unchecked")
    public KeyValuePair<Integer, T>[] getChanged() {
        KeyValuePair<Integer, T>[] changed = new KeyValuePair[bitSet.cardinality()];
        for (int i = bitSet.nextSetBit(0), j = 0; i >= 0; i = bitSet.nextSetBit(i + 1), j++) {
            changed[j] = new KeyValuePair<>(i, values[i]);
        }
        return changed;
    }

    /**
     * @return 属性及对应的值数组. 数组从0开始
     */
    public KeyValuePair<Integer, T>[] getAll() {
        KeyValuePair<Integer, T>[] indexValuePairs = KeyValuePair.newInstances(values.length);
        for (int i = 0, len = indexValuePairs.length; i < len; i++) {
            indexValuePairs[i] = new KeyValuePair<>(i, values[i]);
        }
        return indexValuePairs;
    }
}